using Kopernikus.Collections.Generic;
using Kopernikus.Parsing.Utility;

namespace Kopernikus.Parsing.GrammarSets
{
    public class ReachableGrammarProductions
    {
        private readonly IGrammar m_grammar;
        private Set<Production> m_reachableProductions;

        public ReachableGrammarProductions(IGrammar grammar)
        {
            m_grammar = grammar;
        }

        public IGrammar Grammar
        {
            get { return m_grammar; }
        }

        public Set<Production> ReachableProductions
        {
            get
            {
                if (m_reachableProductions == null)
                {
                    m_reachableProductions = new Set<Production>();
                    m_reachableProductions.Add(Grammar.StartProductions);

                    ProductionsByLHS productionsByLHS = new ProductionsByLHS(Grammar);

                    WorkList<Symbol> lhsList = new WorkList<Symbol>(false);

                    Grammar.StartProductions.Each(delegate(Production p) { lhsList.Enqueue(p.LHS); });

                    Symbol lhs;
                    while (lhsList.Dequeue(out lhs))
                    {
                        Set<Production> productions = productionsByLHS.GetProductionsByLHS(lhs);
                        foreach (Production p in productions)
                        {
                            lhsList.Enqueue(p.RHS);
                            m_reachableProductions.Add(p);
                        }
                    }
                }
                return m_reachableProductions;
            }
        }
    }
}